package fr.cdj.thebox.client.content;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.customware.gwt.presenter.client.EventBus;
import net.customware.gwt.presenter.client.widget.WidgetPresenter;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.Window;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;

import fr.cdj.thebox.client.content.ui.FileItemDisplay;
import fr.cdj.thebox.client.events.ListFilesRequestEvent;
import fr.cdj.thebox.client.events.ListFilesSuccessEvent;
import fr.cdj.thebox.client.events.ListFilesSuccessHandler;
import fr.cdj.thebox.client.events.SortFilesRequestEvent;
import fr.cdj.thebox.client.events.SortFilesRequestHandler;
import fr.cdj.thebox.shared.FileMetaData;

public class FileItemPresenter extends WidgetPresenter<FileItemDisplay> implements Comparable<FileItemPresenter> {

	public interface Factory {
		FileItemPresenter create(FileMetaData fileMetaData);
	}

	private FileItemPresenter.Factory fileItemPresenterFactory;

	private List<FileItemPresenter> fileItemPresenters;
	private FileItemPresenter parentPresenter;

	private FileMetaData fileMetaData;
	private boolean opened = false;
	private boolean initialized = false;

	@Inject
	public FileItemPresenter(FileItemDisplay.Factory displayFactory, EventBus eventBus, @Assisted FileMetaData fileMetaData) {
		super(displayFactory.create(fileMetaData), eventBus);
		this.fileMetaData = fileMetaData;
		this.fileItemPresenters = new ArrayList<FileItemPresenter>();
	}

	@Override
	protected void onBind() {
		registerHandler(display.getHasItemClickHandlers().addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if (fileMetaData.isDirectory()) {
					if (!initialized) {
						eventBus.fireEvent(new ListFilesRequestEvent(FileItemPresenter.this, fileMetaData.getPath()));
						initialized = true;
						display.setLoading();
					}
					display.setOpened(opened = !opened);
				} else {
					downloadSingleFile();
				}
			}
		}));
		registerHandler(eventBus.addHandler(ListFilesSuccessEvent.getType(), new ListFilesSuccessHandler() {
			@Override
			public void onListFilesSuccess(ListFilesSuccessEvent event) {
				if (event.getEventSource().equals(FileItemPresenter.this) && event.getFileList() != null) {
					for (FileMetaData fileMetaData : event.getFileList().getFilesMetaDatas()) {
						FileItemPresenter fileItemPresenter = fileItemPresenterFactory.create(fileMetaData);
						fileItemPresenter.setFileItemPresenterFactory(fileItemPresenterFactory);
						fileItemPresenter.bind();
						fileItemPresenter.revealDisplay();
						fileItemPresenter.setParentPresenter(FileItemPresenter.this);
						fileItemPresenter.getDisplay().getHasSelectedValue().setValue(display.getHasSelectedValue().getValue(), false);
						fileItemPresenters.add(fileItemPresenter);
					}
					refreshDisplay();
				}
			}
		}));
		registerHandler(display.getHasSelectedValue().addValueChangeHandler(new ValueChangeHandler<Boolean>() {
			@Override
			public void onValueChange(ValueChangeEvent<Boolean> event) {
				notifyParent();
				setChildrenSelected(event.getValue());
			}
		}));
		registerHandler(eventBus.addHandler(SortFilesRequestEvent.getType(), new SortFilesRequestHandler() {
			@Override
			public void onSortFilesRequest(SortFilesRequestEvent event) {
				refreshDisplay();
			}
		}));
	}

	private void notifyParent() {
		if (parentPresenter != null) {
			parentPresenter.childSelected();
		}
	}

	private void childSelected() {
		boolean allChildrenSelected = true;
		for (FileItemPresenter presenter : fileItemPresenters) {
			allChildrenSelected &= presenter.getDisplay().getHasSelectedValue().getValue();
		}
		display.getHasSelectedValue().setValue(allChildrenSelected);
		notifyParent();
	}

	private void refreshDisplay() {
		Collections.sort(fileItemPresenters);
		display.clearItems();
		for (FileItemPresenter presenter : fileItemPresenters) {
			display.addFileItem(presenter.getDisplay());
		}
	}

	@Override
	protected void onUnbind() {
	}

	@Override
	protected void onRevealDisplay() {
	}

	public List<FileMetaData> getMetaDatasSelected() {
		List<FileMetaData> filesMetaDatas = new ArrayList<FileMetaData>();
		if (fileMetaData.isDirectory()) {
			if (display.getHasSelectedValue().getValue()) {
				filesMetaDatas.add(fileMetaData);
			} else {
				for (FileItemPresenter fileItemPresenter : fileItemPresenters) {
					filesMetaDatas.addAll(fileItemPresenter.getMetaDatasSelected());
				}
			}
		} else {
			if (display.getHasSelectedValue().getValue()) {
				filesMetaDatas.add(fileMetaData);
			}
		}
		return filesMetaDatas;
	}

	private void setSelected(boolean selected) {
		display.getHasSelectedValue().setValue(selected, false);
		setChildrenSelected(selected);
	}

	private void setChildrenSelected(boolean selected) {
		if (fileMetaData.isDirectory()) {
			for (FileItemPresenter presenter : fileItemPresenters) {
				presenter.setSelected(selected);
			}
		}
	}

	@Override
	public int compareTo(FileItemPresenter o) {
		return fileMetaData.compareTo(o.fileMetaData);
	}

	public void setParentPresenter(FileItemPresenter parentPresenter) {
		this.parentPresenter = parentPresenter;
	}

	public void setFileItemPresenterFactory(FileItemPresenter.Factory fileItemPresenterFactory) {
		this.fileItemPresenterFactory = fileItemPresenterFactory;
	}

	private void downloadSingleFile() {
		Window.open(GWT.getModuleBaseURL() + "file" + fileMetaData.getPath(), "_self", "");
	}

	public boolean spreadSearch(String search) {
		boolean found = fileMetaData.getName().toLowerCase().contains(search.toLowerCase());
		if (fileMetaData.isDirectory() && opened) {
			for (FileItemPresenter presenter : fileItemPresenters) {
				found |= presenter.spreadSearch(search);
			}
		}
		display.asWidget().setVisible(found);
		return found;
	}

}
